package com.persistence.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.sql.DataSource;

/*******************************************************************************
 *DOCUMENT ME!
 * 
 *@author Diego Iacono
 *@since
 *******************************************************************************/
public abstract class DAOManager {
	private String connectionName = null;
	private DAOConfiguration daoCfg = null;
	private static Hashtable poolConnections = null;

	/***************************************************************************
	 * Creates a new DAOManager object.
	 * 
	 * @param connectionName
	 *            DOCUMENT ME!
	 ***************************************************************************/
	public DAOManager(String connectionName) {
		super();
		setConnectionName(connectionName);
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @return DOCUMENT ME!
	 * @throws DAOException
	 *             DOCUMENT ME!
	 ***************************************************************************/
	public Connection getConnection() throws DAOException {
		try {
			daoCfg = new DAOConfiguration();
			daoCfg.load();

			// Primero probar que no exista dentro del pool local
			DataSource ds = getPoolConnectionLocal();

			if (ds == null) {
				ds = getPoolConnectionJNDI();
			}

			return ds.getConnection();
		} catch (SQLException ex) {
			try {
				Class.forName("com.mysql.jdbc.Driver");

				return DriverManager.getConnection("jdbc:mysql://"
						+ daoCfg.getServer() + ":" + daoCfg.getPort() + "/"
						+ daoCfg.getDatabase() + "?" + daoCfg.getDatabase()
						+ "user=" + daoCfg.getUser() + "password="
						+ daoCfg.getPassword());

			} catch (Exception e) {
				e.printStackTrace();
			}

			throw new DAOException(
					"No se pudo recuperar una conexion del pool ["
							+ getConnectionName() + "]", ex);
		} catch (DAOException ex) {
			try {
				Class.forName("com.mysql.jdbc.Driver");

				return DriverManager
						.getConnection("jdbc:mysql://"
								+ daoCfg.getServer() + ":" + daoCfg.getPort() + "/"
								+ daoCfg.getDatabase() + "?" + daoCfg.getDatabase()
								+ "user=" + daoCfg.getUser() + "password="
								+ daoCfg.getPassword());
			} catch (Exception e) {
				e.printStackTrace();
			}

			throw ex;
		}
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @return DOCUMENT ME!
	 ***************************************************************************/
	private static Hashtable getPoolConnections() {
		if (poolConnections == null) {
			poolConnections = new Hashtable();
		}

		return poolConnections;
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @param name
	 *            DOCUMENT ME!
	 * @param pool
	 *            DOCUMENT ME!
	 ***************************************************************************/
	private synchronized static void addPoolConnection(String name,
			DataSource pool) {
		getPoolConnections().put(name, pool);
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @throws DAOException
	 *             DOCUMENT ME!
	 ***************************************************************************/
	public static void initPoolConnectionsLocal() throws DAOException {
		InitialContext context = null;

		try {
			context = new InitialContext();
			NamingEnumeration pools = context.list("jdbc");
			NameClassPair pool;
			String name;

			while (pools.hasMore()) {
				pool = (NameClassPair) pools.next();
				name = pool.isRelative() ? ("jdbc/" + pool.getName()) : pool
						.getName();
				addPoolConnection(name, getPoolConnectionJNDI(name));
			}
		} catch (NamingException ex) {
			throw new DAOException(
					"No se pudieron recuperar todos los pool de conexiones desde el repositorio JNDI",
					ex);
		} finally {
			if (context != null) {
				try {
					context.close();
				} catch (Exception ex) {
					// TODO Manejar error
					// "No se pudo cerrar el contexto JNDI"
				}
			}
		}
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @return DOCUMENT ME!
	 ***************************************************************************/
	private DataSource getPoolConnectionLocal() {
		return (DataSource) getPoolConnections().get(getConnectionName());
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @param poolName
	 *            DOCUMENT ME!
	 * @return DOCUMENT ME!
	 * @throws DAOException
	 *             DOCUMENT ME!
	 ***************************************************************************/
	private static DataSource getPoolConnectionJNDI(String poolName)
			throws DAOException {
		Context context = null;

		try {
			// TODO Analizar si es necesario
			// Si estamos en debug levanto con el nombre del standar j2ee
			// if (Constantes.FUNCION_SERVIDOR ==
			// Constantes.SERVIDOR_DEBUG_LOCAL) {
			context = (Context) new InitialContext().lookup("java:comp/env");

			// } else {
			// context = (InitialContext)new InitialContext();
			// }
			return (DataSource) context.lookup(poolName);
		} catch (NamingException ex) {
			throw new DAOException("No se pudo recuperar la conexion ["
					+ poolName + "] mediante la busqueda JNDI", ex);
		} catch (Exception e) {
			System.out.println("e" + e.getMessage());
			throw new DAOException("No se pudo recuperar la conexion ["
					+ poolName + "] mediante la busqueda JNDI", e);
		} finally {
			if (context != null) {
				try {
					context.close();
				} catch (Exception ex) {
					// TODO Manejar error
					// "No se pudo cerrar el contexto JNDI"
				}
			}
		}
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @return DOCUMENT ME!
	 * @throws DAOException
	 *             DOCUMENT ME!
	 ***************************************************************************/
	private DataSource getPoolConnectionJNDI() throws DAOException {
		return getPoolConnectionJNDI(getConnectionName());
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @param connection
	 *            DOCUMENT ME!
	 * @param stmt
	 *            DOCUMENT ME!
	 ***************************************************************************/
	protected void closeAll(Connection connection, PreparedStatement stmt) {
		closeAll(connection, stmt, null);
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @param connection
	 *            DOCUMENT ME!
	 ***************************************************************************/
	protected void closeAll(Connection connection) {
		closeAll(connection, null);
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @param stmt
	 *            DOCUMENT ME!
	 * @param rs
	 *            DOCUMENT ME!
	 ***************************************************************************/
	protected void closeAll(PreparedStatement stmt, ResultSet rs) {
		closeAll(null, stmt, rs);
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @param connection
	 *            DOCUMENT ME!
	 * @param stmt
	 *            DOCUMENT ME!
	 * @param rs
	 *            DOCUMENT ME!
	 ***************************************************************************/
	public void closeAll(Connection connection, PreparedStatement stmt,
			ResultSet rs) {
		/* Cerrar result set */
		if (rs != null) {
			try {
				rs.close();
			} catch (Throwable ex) {
				// TODO Manejar error
				// "No se pudo cerrar el result set"
			}
		}

		/* Cerrar statement */
		if (stmt != null) {
			try {
				stmt.close();
			} catch (Throwable ex) {
				// TODO Manejar error
				// "No se pudo cerrar el statement"
			}
		}

		/* Cerrar conexion */
		if (connection != null) {
			try {
				connection.close();
			} catch (Throwable ex) {
				// TODO Manejar error
				// "No se pudo cerrar la conexion"
			}
		}
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @param poolConnections
	 *            DOCUMENT ME!
	 ***************************************************************************/
	public static void setPoolConnections(Hashtable poolConnections) {
		DAOManager.poolConnections = poolConnections;
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @return DOCUMENT ME!
	 ***************************************************************************/
	public String getConnectionName() {
		return connectionName;
	}

	/***************************************************************************
	 * DOCUMENT ME!
	 * 
	 * @param connectionName
	 *            DOCUMENT ME!
	 ***************************************************************************/
	public void setConnectionName(String connectionName) {
		this.connectionName = connectionName;
	}
}
